﻿using System;
using System.Collections.Generic;
using System.Configuration;
using System.Data;
using System.Text;
using System.Linq;
using System.Windows;
using System.Threading;
using System.ServiceModel;
using System.Xml;
using System.Xml.Serialization;

namespace cs2335lab5
{
    namespace Server
    {
        /// <summary>
        /// Interaction logic for App.xaml
        /// </summary>
        public partial class App : Application
        {
            /// <summary>
            /// User manager
            /// </summary>
            public UserManager UManager { get; set; }

            /// <summary>
            /// Issue manager
            /// </summary>
            public IssueManager IManager { get; set; }

            /// <summary>
            /// The main server dialog
            /// </summary>
            public ServerForm Server { get; protected set; }

            /// <summary>
            /// The server network/process connection
            /// </summary>
            public ServiceHost Host { get; protected set; }

            /// <summary>
            /// An accessor for an http URI based on IP and Port
            /// </summary>
            public Uri GetAppHTTPUri(string ip, string port)
            {
                StringBuilder build = new StringBuilder("http://");
                build.Append(ip.ToString());
                build.Append(":");
                build.Append(port.ToString());
                return new Uri(build.ToString());
            }

            /// <summary>
            /// A generator for a TCP URI based on IP and Port
            /// </summary>
            public Uri GetAppTcpUri(string ip, string port)
            {
                StringBuilder build = new StringBuilder("net.tcp://");
                build.Append(ip);
                build.Append(":");
                build.Append(port);
                return new Uri(build.ToString());
            }

            /// <summary>
            /// An accessor for a pipe URI based on IP
            /// </summary>
            public Uri GetAppPipeUri(string ip)
            {
                StringBuilder build = new StringBuilder("net.pipe://");
                build.Append(ip.ToString());
                return new Uri(build.ToString());
            }

            /// <summary>
            /// App constructor
            /// shows the server form and opens up process/network connections
            /// </summary>
            public App()
                : base()
            {

            }

            /// <summary>
            /// Code to execute on startup
            /// </summary>
            /// <param name="sender"></param>
            /// <param name="args"></param>
            void AppStartup(object sender, StartupEventArgs args)
            {
                // show the server form
                ShowServer();
                // you may now make calls to App.WriteLine.

                App.WriteLine("Started the dialog");

                // create manager objects
                CreateUserManager();
                CreateIssueManager();
            }

            /// <summary>
            /// Deserialize the contents of users.xml into a UserManager object
            /// </summary>
            public void CreateUserManager()
            {
                // deserialize or create a new UserManager
                XmlSerializer deserial = new XmlSerializer(typeof(UserManager));
                try
                {
                    System.IO.TextReader read = new System.IO.StreamReader("users.xml");
                    UManager = (UserManager)deserial.Deserialize(read);
                    read.Close();
                    App.WriteLine("Deserialized UserManager from users.xml");
                }
                catch (System.IO.FileNotFoundException)
                {
                    App.WriteLine("Couldn't find users.xml; creating new UserManager");
                    UManager = new UserManager();
                }
                catch (System.Xml.XmlException)
                {
                    App.WriteLine("An error was encountered while parsing the users.xml file!");
                    UManager = new UserManager();
                }
            }

            /// <summary>
            /// Deserialize the contents of issues.xml into an IssueManager object
            /// </summary>
            public void CreateIssueManager()
            {
                // deserialize or create a new IssueManager
                XmlSerializer deserial = new XmlSerializer(typeof(IssueManager));
                try
                {
                    System.IO.TextReader read = new System.IO.StreamReader("issues.xml");
                    IManager = (IssueManager)deserial.Deserialize(read);
                    read.Close();
                    App.WriteLine("Deserialized IssueManager from issues.xml");
                }
                catch (System.IO.FileNotFoundException)
                {
                    App.WriteLine("Couldn't find issues.xml; creating new IssueManager");
                    IManager = new IssueManager();
                }
                catch (System.Xml.XmlException)
                {
                    App.WriteLine("Error while parsing issues.xml!");
                    IManager = new IssueManager();
                }
                catch (Exception ex)
                {
                    // print out exception and inner exception if available
                    StringBuilder b = new StringBuilder("Error parsing issues.xml: ");
                    b.Append(ex.Message);
                    if (ex.InnerException != null)
                    {
                        b.Append(" ");
                        b.Append(ex.InnerException.Message);
                    }
                    App.WriteLine(b.ToString());
                    IManager = new IssueManager();
                }
            }

            /// <summary>
            /// Connect to the server at the provided IP and port
            /// </summary>
            /// <param name="ip"></param>
            /// <param name="port"></param>
            public void Connect(string ip, string port)
            {
                // tell the dialog what we're doing
                StringBuilder sb = new StringBuilder("Set the host to ");
                sb.Append(ip.ToString());
                sb.Append(" and the port to ");
                sb.Append(port.ToString());
                App.WriteLine(sb.ToString());

                // make sure we're disconnected before connecting
                Disconnect();

                Uri AppTcpUri = GetAppTcpUri(ip, port);

                // create a new ServiceHost with our URIs
                Host = new ServiceHost(typeof(NetworkManager), AppTcpUri);
                App.WriteLine("Created the ServiceHost");

                // configure the net binding
                NetTcpBinding b = new NetTcpBinding();
                b.ReceiveTimeout = TimeSpan.MaxValue;
                b.SendTimeout = TimeSpan.MaxValue;
                b.MaxBufferSize = Int32.MaxValue;
                b.CloseTimeout = TimeSpan.MaxValue;
                b.MaxReceivedMessageSize = Int32.MaxValue;

                // attach the service endpoint; prevent timeouts by specifying a max timeout on the net binding
                Host.AddServiceEndpoint(typeof(Data.INetworkManager), b, "TcpIssueManager");

                App.WriteLine("Added the service endpoints");

                // open the connection
                Host.Open();
                App.WriteLine("Opened the service");
            }

            /// <summary>
            /// Close the connection if it's open.
            /// </summary>
            public void Disconnect()
            {
                // make sure we don't throw a null ref exception
                if (Host != null)
                {
                    // kill it with fire (also death)
                    Host.Close();
                    Host = null;
                    App.WriteLine("Disconnected");
                }
            }

            /// <summary>
            /// Override the OnExit method to close the network connection if it's open
            /// </summary>
            /// <param name="e"></param>
            protected override void OnExit(ExitEventArgs e)
            {
                Disconnect();

                base.OnExit(e);
            }

            /// <summary>
            /// Show the ServerForm window
            /// </summary>
            public void ShowServer()
            {
                if (Server == null)
                {
                    Server = new ServerForm();
                }

                Server.Show();
            }

            /// <summary>
            /// Singleton method to access the App-specific functions 
            /// without needing to cast
            /// </summary>
            /// <returns></returns>
            public static App Instance()
            {
                return ((App)App.Current);
            }

            /// <summary>
            /// Sort of a static Console.Writeline type method for the server
            /// </summary>
            /// <param name="text"></param>
            public static void WriteLine(string text)
            {
                ((App)App.Current).Server.WriteLine(text);
            }
        }
    }
}

